/**
 * 项目 跑得快 游戏数据源
 * MVC设计模式中的module模块
 */

import { App } from "../../../../src/App";
import { EventConst } from "../../../../src/core/EventConst";
import { GameSvrsID, ProtocolCmd, ProtocolProxy } from "../../../src/Protocol";
import BaseModel, { UserData } from "../../../src/BaseModule";
import NetParser from "../../../src/NetParser";
import { SingleGame } from "./SingleGame";
import { PokerData, PokerType } from "../../../src/BaseLogic";
import RewardVideo, { AdType } from "./RewardVideo";
import Map from "../../../../src/core/Map";

const MAX_WAIT_TIME:number = 12; // 等待出牌时间
const MAX_SEAT: number = 3; // 最大座位数
const MAX_HAND_POKERS:number = 17; // 每人最大手牌数

// 扑克资源索引
const PokerArray = [
    1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13,
    17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
    33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
    49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
    62, 63, // 62小王 63大王(101=A 102=2)
];
export enum  PlayerIdentity{
    none = 0,
    landlord,
    farmer,
};

export interface EntryRoom{
    seat:number,
    user:UserData,
}

export interface Ready{
    seat:number,
    next:number,
}

export interface Deal{
    info:{
        seat:number,
        cards:PokerData[],
        first:number,
    }[],
    baseCards:PokerData[],
};

export interface CreateLandlord{
    seat:number,
    score:number,
    cards:PokerData[],
}

export interface Discard{
    cards:PokerData[], //打出的牌组信息
    seat:number,       // 谁出的
    next:number,       // 下家
    delayTime:number,  // 延迟出牌时间 
};

export interface CallScore{
    seat:number,
    next:number,
    score:number,
};
// 结算信息
export interface Settlement{
    win:PlayerIdentity,
    spring:number, // 0春天 1反春
    info:{
        name:string; // 玩家名
        seat:number, 
        flag:number; // 身份  
        score:number;// 本局赢分 
    }[]   
};

// 控制事件定义
export const LandlordEvents = {
    EC_ENTRY_ROOM:'ctrl_event_entry_room', // 进入房间
    EC_EXIT_ROOM:'ctrl_event_exit_room', // 离开房间
    EC_READY : 'ctrl_event_ready',        // 准备
    EC_DEAL : 'ctrl_event_deal',          // 发牌
    EC_NOTICE_CALL:'ctrl_event_notice_call', // 通知叫分
    EC_CALL : 'ctrl_event_jiao_fen',        // 0：不抢,1,2,3
    EC_TURN_CALL:'ctrl_event_turn_jiao_fen',// 轮询叫分
    EC_BUILD_BANKER:'ctrl_event_build_banker', // 产生地主
    EC_GAME_START : 'ctrl_event_game_start', // 游戲開始
    EC_WAIT_TIME: 'ctrl_event_wait_time', // 等待出牌时间
    EC_DISCARD : 'ctrl_event_chupai',     // 出牌
    EC_NOTICE_DISCARD : 'ctrl_even_tnotice_chupai',  // 通知出牌
    EC_GAME_RESSET : 'ctrl_event_game_reset', // 游戏重新
    EC_GAME_OVER : 'ctrl_event_game_over',   // 游戏结算
    EC_TRUSTEEESHIP_GAME : 'ctrl_event_trusteeship _game', // 托管
    EC_UPDATE_USER_INFO : 'ctrl_event_update_user_info',
    EC_CHANGE_PLAYER : 'ctrl_event_change_player',            //userdata=userId
    EC_WATCH_VIDEO:'ctrl_watch_video', // 观看视频
};

// 登陆类型
export enum LoginType{
    Unknow = -1,
    Single,
    Guest,
    Wechat,
    QQ,
    ByteDance,
    Max
}

const MAX_POKER_COUNT = 54;
class gameModule extends BaseModel {
    private _titles:any[] = [];
    private _nextPlayer:string = '';
    private _pokerRes:Map<number,cc.SpriteFrame> = new Map<number,cc.SpriteFrame>();

    public get pokerTable():number[]{return PokerArray;}
    public get MaxSeat():number {return MAX_SEAT;}
    public get MaxWaitTime():number {return MAX_WAIT_TIME;}
    public get MaxPokers():number {return MAX_POKER_COUNT;}
    public get MaxHands():number {return MAX_HAND_POKERS;}
    public get NextPlayer():string{return this._nextPlayer;}
    public set setNext(v:string){this._nextPlayer = v;}

    public getPokerSprite(num:number):cc.SpriteFrame{return this._pokerRes.find(num)}
        
    /**
     * 根据用户分数获取标签
     * @param score 
     * @returns 
     */
    public userTitle(score:number):string{
        if (this._titles.length < 1) this._titles = App.getCfg('titles');
        for (let it of this._titles){
            if (it.score[0] <= score && it.score[1] >= score) 
                return it.title;
        }
        return '';
    }

    /**
     * 获取下家
     * @param cur 当前玩家 
     * @returns 
     */
    public getNext(cur:number):number{
        return App.Util.getNextOrBack([0,1,2],cur,true);
    }

    /**
     * 获取最后一家出牌信息
     */
    public getLast(seatIdx:number,discard:Map<number,PokerData[]>):Discard{
        if (!discard || discard.size < 1) 
            return {seat:seatIdx,cards:[],next:-1,delayTime:-1};

        const seats = [0,1,2];
        
        let last = App.Util.getNextOrBack(seats,seatIdx,false);
        let find = discard.find(last);

        // 上家过牌，再找上上一家
        if (find){
            // 上上一家出牌情况
            if (find.length < 1){
                last = App.Util.getNextOrBack(seats,last,false);
                find = discard.find(last);
            }
            if (!find || find.length > 0){
                return {seat:last,cards:find,next:-1,delayTime:-1};
            }
        }

        //自己是第一个出牌的或者前面两家都是过牌，则当前轮自己必须出牌，不能过牌
        return {seat:seatIdx,cards:[],next:-1,delayTime:-1};
    }

    protected onInit() {
        super.onInit();
        this._nodePool = new cc.NodePool(); // 创建牌池
        PokerArray.forEach((idx)=>{
            App.Res.loadRes(`poker/${idx}:room`,cc.Texture2D,(t2d:cc.Texture2D)=>{
                this._pokerRes.inset(idx,new cc.SpriteFrame(t2d));
            });
        });

        // 监听结算，设置游戏状态
        App.Event.on(LandlordEvents.EC_GAME_OVER, ()=>{this.playing=false;}, this);

        // 观看短视频
        App.Event.on(LandlordEvents.EC_WATCH_VIDEO,()=>{
            const AD:string = App.getCfg(`rewardAd`)[this.isSingle?0:1];
            RewardVideo.playRewardVideo(AD,GameModule.userInfo.OpenID,(data:any)=>{
                console.log(`playRewardVideo(${data})`);
                const rewards = App.getCfg('reward');
                this.isSingle && (this._userData.Coin += (data.RewardCount*rewards[0]));
                App.Event.emit(LandlordEvents.EC_UPDATE_USER_INFO,this._userData);
                App.setLocalStorage(this._userData,App.LOCAL_KEY.USER);
            });
        },this);
        console.log('onInit')
    }

    protected onDestroy(){
        this._isSingle && SingleGame.destroy();
        App.Event.offAll(this);
        super.onDestroy();
        console.log('onDestroy')
    }
    
    protected onEntry(cfg:any){
        this._roomData = this._isSingle ? SingleGame.randomRoom : cfg;
        if (!this._roomData){
            App.popTips(App.getText('landlord.invalid_room'));
            return ;
        }

        if (this._roomData.BetMin <= this._userData.Coin){
            const count:string = this._isSingle ? App.Util.formatScore(this._roomData.BetMin) : '1';
            const tips = App.Util.format(App.getText('landlord.entry_ask'),count,App.getCfg('goods')[this._isSingle?0:1]);
            App.MessageBox(tips,(flag:number)=>{
                if (flag === App.MB_FLAG.OK){
                    this.isSingle && (this._userData.Coin -= this._roomData.BetMin);
                    App.Event.emit(LandlordEvents.EC_UPDATE_USER_INFO,this._userData);
                    App.setLocalStorage(this._userData,App.LOCAL_KEY.USER);
                    App.runScene('RoomScene:game',()=>{
                        SingleGame.entryRoom();
                        this._isInRoom=true;
                    });
                }
            });
        } else {
            App.MessageBox(App.getText('landlord.no_factor'),(flag:number)=>{
                flag === App.MB_FLAG.OK && App.Event.emit(LandlordEvents.EC_WATCH_VIDEO);
            });
        }

        if (!cfg){
            if (!this._isSingle){
            }
            this._roomData = SingleGame.randomRoom;
            return ;
        } 
        if (cfg.BetMin <= this._userData.Coin){
            this._roomData = cfg;
            App.runScene('RoomScene:game',()=>{this._isInRoom=true;});
            return ;
        }

        App.popTips(App.getText('noCoin'));
    }

    protected onStart(cfgID:number){
        if (this.isSingle){
            SingleGame.startGame();
            return ;
        }
        
        App.send({
            Protocol: ProtocolCmd.GS2C_MainGameProto,
            Protocol2: ProtocolCmd.C2GS_EntrGameProto2,
            RoomType:cfgID,
        },'GS2C_EntrGameProto2',(data:any)=>{
        });
    }
    protected onFireCard(roomID:string,list:number[]){
        if (this.isSingle){
            SingleGame.fireCard(list);
            return ;
        }
        App.send({
            Protocol: ProtocolCmd.GS2C_MainGameProto,
            Protocol2: ProtocolCmd.C2GS_PlayerPlayCardsProto2,
            RoomId: roomID,
            CardNum: list
        });
    }
    protected onExit(){
        if (this.isSingle){
            SingleGame.exitRoom();
            App.runScene('HallScene:hall');
            this._nodePool.clear();
            this._isInRoom = false;
            return ;
        }

        let pkg = {
            Protocol: ProtocolCmd.GS2C_MainGameProto,
            Protocol2: ProtocolCmd.C2GS_PlayerQuitProto2
        };
        App.send(pkg,'GS2C_PlayerQuitProto2',()=>{
            App.runScene('HallScene:hall');
            this._nodePool.clear();
            this._isInRoom = false;
        });
    }
    
    protected onTrusteeship(){
        if (this.isSingle){
            this._isTrusteeship = true;
            SingleGame.trusteeship();
            return ;
        }
        App.send({
            Protocol: ProtocolCmd.GS2C_MainGameProto,
            Protocol2: ProtocolCmd.C2GS_PlayerTrusteeShipProto2
        });
        
    }

    protected onLogin(type:number){
        App.Event.emit(EventConst.LOCK_SCREEN, true,true);
        this._isSingle = type === LoginType.Single;
        if (this._isSingle){
            App.popTips(App.getText('entry_game'));
            SingleGame.init();
            this._userData = SingleGame.userData;
            this._rankInfo = SingleGame.rankInfo.slice(0);
            setTimeout(() => {
                App.setLocalStorage({
                    loginType:type,
                    lastTime:(new Date()).getTime(),
                    token:'',
                    svrUrl:''
                },App.LOCAL_KEY.LOGIN);
                App.Event.emit(EventConst.LOGIN_SUCCESS);
                App.Event.emit(EventConst.LOCK_SCREEN,false,false);
            }, 1000);
            return ;
        }

        App.popTips(App.getText('login'));
        let _local = App.getLocalStorage(App.LOCAL_KEY.LOGIN);
        let _svrUrl = _local.svrUrl;
        let _success = ()=>{
            App.setLocalStorage(this._loginData,App.LOCAL_KEY.LOGIN);
            App.Event.on(EventConst.SOCKET_AGAIN_CONNETED, this.onSocket, this);
            // 绑定网络解析器
            let _parser = new NetParser();
            _parser.init(GameModule.MainProtocol,GameSvrsID.DDZ);
            App.Event.emit(EventConst.SOCKET_BIND,_parser);
            App.Event.emit(EventConst.SOCKET_CONNETED,_svrUrl,this.onSocket.bind(this));
        };
        if (App.Util.isEmpty(_local.token) || App.Util.isEmpty(_svrUrl)){
            let url = App.getCfg('loginSvr');
            this._loginSDK(type,(data:Object)=>{
                App.http(url,data,true,(is:boolean,data:any)=>{
                    if (is){
                        App.popTips(App.getText('entry_game'));
                        data = JSON.parse(App.String.decode64(data));
                        if (!App.Util.isEmpty(data.Token) && !App.Util.isEmpty(data.Url)){
                            App.SvrList = data.ServerList;
                            _svrUrl = `${data.Url}/${App.getCfg('wsData')}`;
                            data.Url.indexOf('ws://') === -1 && (_svrUrl = `ws://${_svrUrl}`);
                            this._loginData = {
                                loginType:type,
                                lastTime:(new Date()).getTime(),
                                token:data.Token,
                                svrUrl:_svrUrl
                            };
                            _success();
                            return ;
                        }
                    }
                    App.Event.emit(EventConst.LOCK_SCREEN, false,false);
                    App.popTips(App.getText('socket.login_error'));
                });
            });
        } else {
            this._loginData = {
                loginType:type,
                lastTime:(new Date()).getTime(),
                token:_local.token,
                svrUrl:_svrUrl
            };
            _success();
        }
    }
    protected onLogout(){
        this.destroy();
        App.logout = true;
        App.runScene('LoginScene:hall',()=>{
            App.Event.emit(EventConst.START_LOGOUT);
        });
    }

    protected onSocket(is:boolean){
        if (!is){
            App.popTips(App.getText('socket.net_error'));
            return ;
        }
        // 发送链接 到登录成功
        let _openID:string = '';
        App.send({
            Protocol: this.MainProtocol,
            Protocol2: ProtocolProxy.C2Proxy_ConnDataProto,
        },'Proxy2C_ConnDataProto',(data:any)=>{
            if (data.Protocol === this.MainProtocol){
                _openID = data.OpenID;
                let json = {
                    Protocol: ProtocolProxy.Proxy2G_SendDataProto,
                    Protocol2: ProtocolProxy.C2Proxy_SendDataProto,
                    Token: this._loginData.token,
                };
                App.send(json,'Proxy2C_SendDataProto',(data:any)=>{
                    App.Util.isEmpty(data.UserData.UserName) && (data.UserData.UserName = `guest_user`);
                    data.UserData.Token = this._loginData.token;
                    data.UserData.OpenID=_openID;
                    if (data.UserData.Avatar < 2) {
                        const avatar = App.Util.random(2,18);
                        data.UserData.Avatar = avatar;
                        App.send({
                            Protocol: ProtocolCmd.GS2C_MainHallProto,
                            Protocol2: ProtocolCmd.C2GS_HallPersonalCenterChangeHeadUrlProto2,
                            HeadUrlID: avatar
                        });

                    }
                    this.setUser(data.UserData);
                    App.Event.emit(EventConst.LOGIN_SUCCESS);
                    App.Event.emit(EventConst.LOCK_SCREEN,false,false);

                });
            }
        });
    }

    private _loginSDK(type:LoginType,call:(dt:any)=>void){
        if (type === LoginType.Guest){
            call({
                app:App.ModuleName,
                flag: LoginType[type],
                AccountName: `${`guest_${(new Date()).getTime()}`}`, AccountPw: '123456'
            });
            return ;
        }

        // 渠道登录
        App.Event.emit(EventConst.LOCK_SCREEN,false,false);
        App.Event.on('channellogin',(auth:any)=>{
            App.Event.emit(EventConst.LOCK_SCREEN,true,true);
            call({
                app:App.ModuleName,
                flag: LoginType[type],
                data: auth
            });
        },this);
        App.Native.callNative('channellogin',{channel:LoginType[type]});
    }
}
export const GameModule: gameModule = gameModule.getInstance<gameModule>(gameModule);
